package com.xjj.QRCode;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

import static com.google.zxing.client.j2se.MatrixToImageWriter.toBufferedImage;

public class QRCodeUtils {
    private static final String CHARSET = "utf-8";
    // 二维码尺寸
    private static final int QRCODE_SIZE = 300;

    public static BufferedImage createImage(String url) throws Exception {
        Hashtable hints = new Hashtable();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,
                hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        return image;
    }
   /**
    * 生成二维码并下载
    *
    * @param url      二维码的内容
    * @param path     二维码保存路径
    * @param fileName 二维码保存名称
    * @return BitMatrix对象
    */
   public static void createCode(String url, String path, String fileName) throws IOException {
      //其他参数，如字符集编码
      Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
      hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
      //容错级别为H
      hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
      //白边的宽度，可取0~4
      hints.put(EncodeHintType.MARGIN, 0);
      BitMatrix bitMatrix = null;
      try {
         bitMatrix = new MultiFormatWriter().encode(url,
               BarcodeFormat.QR_CODE, 256, 256, hints); //解码url，设置二维码宽高256px
         File file = new File(path, fileName); //设置二维码路径&名字
         writeToFile(bitMatrix, "jpg", file); //下载二维码，格式jpg
      } catch (WriterException e) {
         e.printStackTrace();
      }
   }

   /**
    * 二维码下载方法
    * @param url
    * @param fileName
    * @param request
    * @param response
    */
   public static void downFile(String url, String fileName, HttpServletRequest request, HttpServletResponse response) {
      try {
         //1.定义ContentType为("multipart/form-data")让浏览器自己解析文件格式
         response.setContentType("multipart/form-data");
         //2.中文名转码
         //response.setHeader("Content-disposition", "attachment; filename=\""+encodeChineseDownloadFileName(request, fileName+".xlsx") +"\"");
         response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes("UTF-8"), "ISO-8859-1"));
         //获得文件
         File file = new File(url+fileName);
         FileInputStream in = new FileInputStream(file);
         //3.将文件写入缓冲区OutputStream(out)
         OutputStream out = new BufferedOutputStream(response.getOutputStream());
         int b = 0;
         byte[] buffer = new byte[2048];
         while ((b=in.read(buffer)) != -1){
            //4.将缓冲区文件输出到客户端(out)
            out.write(buffer,0,b);
         }
         in.close();
         out.flush();
         out.close();
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
    
    /**
	 * 二维码写入文件方法
	 *
	 * @param matrix 二维码BitMatrix对象
	 * @param format 下载图片格式
	 * @param file   二维码文件对象，包含文件路径&名称
	 * @throws IOException
	 */
	static void writeToFile(BitMatrix matrix, String format, File file) throws IOException {
		BufferedImage image = toBufferedImage(matrix);
		if (!ImageIO.write(image, format, file)) {
			throw new IOException("Could not write an image of format " + format + " to " + file);
		}
	}
}
